From d54b7dec94d5a756453aadcc59f51f509cf1049b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 30 Apr 2020 18:53:02 +0100 Subject: [PATCH] Remove gtk_dialog_run() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Nested main loops are bad, as they introduce layers of complexity caused by the potential re-entrancy in the case of multiple event sources, like IPC, threads, etc. Additionally, the programming model they provide—stop the world while spinning a new loop—does not conform to the event-driven model employed by GTK. --- docs/reference/gtk/gtk4-sections.txt | 1 - gtk/gtkdialog.c | 172 +-------------------------- gtk/gtkdialog.h | 4 - 3 files changed, 2 insertions(+), 175 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 68c436cf84..1daaa1ad22 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -678,7 +678,6 @@ GtkDialogFlags GtkResponseType gtk_dialog_new gtk_dialog_new_with_buttons -gtk_dialog_run gtk_dialog_response gtk_dialog_add_button gtk_dialog_add_buttons diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c index bab86685aa..f5c401311a 100644 --- a/gtk/gtkdialog.c +++ b/gtk/gtkdialog.c @@ -83,12 +83,6 @@ * a dialog receives a delete event, the #GtkDialog::response signal will * be emitted with a response ID of #GTK_RESPONSE_DELETE_EVENT. * - * If you want to block waiting for a dialog to return before returning - * control flow to your code, you can call gtk_dialog_run(). This function - * enters a recursive main loop and waits for the user to respond to the - * dialog, returning the response ID corresponding to the button the user - * clicked. - * * For the simple dialog in the following example, in reality you’d probably * use #GtkMessageDialog to save yourself some effort. But you’d need to * create the dialog contents manually if you had more than a simple message @@ -592,7 +586,6 @@ gtk_dialog_buildable_interface_init (GtkBuildableIface *iface) static gboolean gtk_dialog_close_request (GtkWindow *window) { - /* emit response signal, this will shut down the loop if we are in gtk_dialog_run */ gtk_dialog_response (GTK_DIALOG (window), GTK_RESPONSE_DELETE_EVENT); return GTK_WINDOW_CLASS (gtk_dialog_parent_class)->close_request (window); @@ -1011,9 +1004,8 @@ gtk_dialog_set_default_response (GtkDialog *dialog, * @response_id: response ID * * Emits the #GtkDialog::response signal with the given response ID. - * Used to indicate that the user has responded to the dialog in some way; - * typically either you or gtk_dialog_run() will be monitoring the - * ::response signal and take appropriate action. + * + * Used to indicate that the user has responded to the dialog in some way. **/ void gtk_dialog_response (GtkDialog *dialog, @@ -1027,166 +1019,6 @@ gtk_dialog_response (GtkDialog *dialog, response_id); } -typedef struct -{ - GtkDialog *dialog; - gint response_id; - GMainLoop *loop; - gboolean destroyed; -} RunInfo; - -static void -shutdown_loop (RunInfo *ri) -{ - if (g_main_loop_is_running (ri->loop)) - g_main_loop_quit (ri->loop); -} - -static void -run_unmap_handler (GtkDialog *dialog, gpointer data) -{ - RunInfo *ri = data; - - shutdown_loop (ri); -} - -static void -run_response_handler (GtkDialog *dialog, - gint response_id, - gpointer data) -{ - RunInfo *ri; - - ri = data; - - ri->response_id = response_id; - - shutdown_loop (ri); -} - -static void -run_destroy_handler (GtkDialog *dialog, gpointer data) -{ - RunInfo *ri = data; - - /* shutdown_loop will be called by run_unmap_handler */ - - ri->destroyed = TRUE; -} - -/** - * gtk_dialog_run: - * @dialog: a #GtkDialog - * - * Blocks in a recursive main loop until the @dialog either emits the - * #GtkDialog::response signal, or is destroyed. If the dialog is - * destroyed during the call to gtk_dialog_run(), gtk_dialog_run() returns - * #GTK_RESPONSE_NONE. Otherwise, it returns the response ID from the - * ::response signal emission. - * - * Before entering the recursive main loop, gtk_dialog_run() calls - * gtk_widget_show() on the dialog for you. Note that you still - * need to show any children of the dialog yourself. - * - * During gtk_dialog_run(), the default behavior of delete events - * is disabled; if the dialog receives a delete event, it will not be - * destroyed as windows usually are, and gtk_dialog_run() will return - * #GTK_RESPONSE_DELETE_EVENT. Also, during gtk_dialog_run() the dialog - * will be modal. You can force gtk_dialog_run() to return at any time by - * calling gtk_dialog_response() to emit the ::response signal. Destroying - * the dialog during gtk_dialog_run() is a very bad idea, because your - * post-run code won’t know whether the dialog was destroyed or not. - * - * After gtk_dialog_run() returns, you are responsible for hiding or - * destroying the dialog if you wish to do so. - * - * Typical usage of this function might be: - * |[ - * GtkWidget *dialog = gtk_dialog_new (); - * // Set up dialog... - * - * int result = gtk_dialog_run (GTK_DIALOG (dialog)); - * switch (result) - * { - * case GTK_RESPONSE_ACCEPT: - * // do_application_specific_something (); - * break; - * default: - * // do_nothing_since_dialog_was_cancelled (); - * break; - * } - * gtk_window_destroy (dialog); - * ]| - * - * Note that even though the recursive main loop gives the effect of a - * modal dialog (it prevents the user from interacting with other - * windows in the same window group while the dialog is run), callbacks - * such as timeouts, IO channel watches, DND drops, etc, will - * be triggered during a gtk_dialog_run() call. - * - * Returns: response ID - **/ -gint -gtk_dialog_run (GtkDialog *dialog) -{ - RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL, FALSE }; - gboolean was_modal; - gboolean was_hide_on_close; - gulong response_handler; - gulong unmap_handler; - gulong destroy_handler; - - g_return_val_if_fail (GTK_IS_DIALOG (dialog), -1); - - g_object_ref (dialog); - - was_modal = gtk_window_get_modal (GTK_WINDOW (dialog)); - gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - was_hide_on_close = gtk_window_get_hide_on_close (GTK_WINDOW (dialog)); - gtk_window_set_hide_on_close (GTK_WINDOW (dialog), TRUE); - - if (!gtk_widget_get_visible (GTK_WIDGET (dialog))) - gtk_widget_show (GTK_WIDGET (dialog)); - - response_handler = - g_signal_connect (dialog, - "response", - G_CALLBACK (run_response_handler), - &ri); - - unmap_handler = - g_signal_connect (dialog, - "unmap", - G_CALLBACK (run_unmap_handler), - &ri); - - destroy_handler = - g_signal_connect (dialog, - "destroy", - G_CALLBACK (run_destroy_handler), - &ri); - - ri.loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (ri.loop); - g_main_loop_unref (ri.loop); - - ri.loop = NULL; - - if (!ri.destroyed) - { - gtk_window_set_modal (GTK_WINDOW (dialog), was_modal); - gtk_window_set_hide_on_close (GTK_WINDOW (dialog), was_hide_on_close); - - g_signal_handler_disconnect (dialog, response_handler); - g_signal_handler_disconnect (dialog, unmap_handler); - g_signal_handler_disconnect (dialog, destroy_handler); - } - - g_object_unref (dialog); - - return ri.response_id; -} - /** * gtk_dialog_get_widget_for_response: * @dialog: a #GtkDialog diff --git a/gtk/gtkdialog.h b/gtk/gtkdialog.h index 056253041d..b653017661 100644 --- a/gtk/gtkdialog.h +++ b/gtk/gtkdialog.h @@ -176,10 +176,6 @@ GDK_AVAILABLE_IN_ALL void gtk_dialog_response (GtkDialog *dialog, gint response_id); -/* Returns response_id */ -GDK_AVAILABLE_IN_ALL -gint gtk_dialog_run (GtkDialog *dialog); - GDK_AVAILABLE_IN_ALL GtkWidget * gtk_dialog_get_content_area (GtkDialog *dialog); GDK_AVAILABLE_IN_ALL -- 2.30.2